import tkinter as tk
from tkinter import ttk

class ToolTip:
    def __init__(self, widget, text=None, delay=500, **kwargs):
        self.widget = widget
        self.text = text or widget.cget('text')  # Use widget text if no custom text provided
        self.delay = delay
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0

        # Style configuration with defaults that can be overridden
        self.style = {
            'background': '#ffffe0',
            'foreground': '#000000',
            'relief': tk.SOLID,
            'borderwidth': 1,
            'padding': (3, 1),
            'font': ('TkDefaultFont', 10)
        }
        self.style.update(kwargs)

        self.widget.bind("<Enter>", self.enter)
        self.widget.bind("<Leave>", self.leave)
        self.widget.bind("<ButtonPress>", self.leave)

    def enter(self, event=None):
        self.schedule()

    def leave(self, event=None):
        self.unschedule()
        self.hidetip()

    def schedule(self):
        self.unschedule()
        self.id = self.widget.after(self.delay, self.showtip)

    def unschedule(self):
        if self.id:
            self.widget.after_cancel(self.id)
        self.id = None

    def showtip(self, event=None):
        """Display text in tooltip window with proper positioning"""
        if self.tipwindow or not self.text:
            return

        # Get the current mouse position
        x, y = self.widget.winfo_pointerxy()

        # Create the tooltip window
        root = tk.Tk()
        root.withdraw()  # 隐藏主窗口

        #self.tipwindow = tw = tk.Toplevel(self.widget)
        self.tipwindow = tw = tk.Toplevel(root)
        tw.wm_overrideredirect(True)

        # Calculate optimal position (avoid going off-screen)
        tw.update_idletasks()  # Needed to get accurate window dimensions
        width = tw.winfo_reqwidth()
        height = tw.winfo_reqheight()

        # Adjust position if tooltip would go off-screen
        screen_width = self.widget.winfo_screenwidth()
        screen_height = self.widget.winfo_screenheight()

        if x + width + 20 > screen_width:
            x = screen_width - width - 5
        else:
            x = x + 20

        if y + height + 20 > screen_height:
            y = screen_height - height - 5
        else:
            y = y + 10

        tw.wm_geometry(f"+{x}+{y}")

        # Create and pack the label with styling
        label = tk.Label(tw, text=self.text, justify=tk.LEFT,
                         background=self.style['background'],
                         foreground=self.style['foreground'],
                         relief=self.style['relief'],
                         borderwidth=self.style['borderwidth'],
                         font=self.style['font'],
                         padx=self.style['padding'][0],
                         pady=self.style['padding'][1])
        label.pack()

    def hidetip(self):
        tw = self.tipwindow
        self.tipwindow = None
        if tw:
            tw.destroy()


# Demo application
def create_demo():
    root = tk.Tk()
    root.title("Enhanced ToolTip Demo")
    root.geometry("300x200")

    # Frame for buttons
    frame = ttk.Frame(root, padding="20")
    frame.pack(fill=tk.BOTH, expand=True)

    # Button with default tooltip (uses button text)
    btn1 = ttk.Button(frame, text="Button with default tooltip")
    btn1.pack(pady=10)
    ToolTip(btn1)

    # Button with custom tooltip
    btn2 = ttk.Button(frame, text="Button with custom tooltip")
    btn2.pack(pady=10)
    ToolTip(btn2, text="This is a custom tooltip message",
            background="#e0ffff", foreground="#006600")

    # Button with delayed tooltip
    btn3 = ttk.Button(frame, text="Button with delayed tooltip")
    btn3.pack(pady=10)
    ToolTip(btn3, text="This tooltip appears after 2 seconds", delay=2000,
            background="#ffe0e0", font=('Arial', 12, 'bold'))

    # Entry field with tooltip
    entry = ttk.Entry(frame, width=20)
    entry.pack(pady=10)
    entry.insert(0, "Hover over this field")
    ToolTip(entry, text="This is an entry field tooltip")

    root.mainloop()


if __name__ == "__main__":
    create_demo()